CMake 에 대해

Cover Image for CMake 에 대해
#CMake

2025-1 컴퓨터비전 과목에서 처음으로 CMake 를 접하였다.

인턴쉽을 진행하며 교육자료로 사용할 ROS 패키지들을 개발하면서도 CMake 의 편의성을 여럿 느껴왔다. (ROS 에서는 catkin, colcon 빌드 시스템을 사용한다. 이는 CMake 를 ROS 시스템에 맞게 expand 한 것)

주제별로 subdirectory 를 두고 여러 소스코드를 한번에 컴파일하고 빌드할 수 있다는 점 그리고 복잡한 빌드 의존성을 쉽게 해결할 수 있다는 점이 신세계였다.

  • cli 명령어로 소스코드를 빌드하는 경우, 헤더파일이랑 내외부라이브러리의 경로를 명시해서 링킹해주는 작업을 직접 해주어야한다.
  • ex) g++ main.cpp -o main -I /usr/local/include/opencv -L /usr/local/bin -l opencv_core ...

참고로, cmake 자체는 빌드나 컴파일하는데 사용되지 않는다. 진짜 컴파일&빌드는 make 이 하는거고, cmake 는 빌드를 위한 빌드파일들을 생성하는 역할이다.

CMakeLists 를 작성하는 방법을 기록해놓고자한다.

1. workspace 생성하기

먼저, 작업공간을 만들자.

기본 틀은 아래와 같다.

cmake_ex
├── CMakeLists.txt ...(1)
└── src

가장 상위 폴더에 CMakeLists.txt 를 생성해 현재 프로젝트의 메타데이터를 기록해두어야한다.

1.1 CMakeLists.txt

가장 상위 폴더의 CMakeLists.txt (1) 에는 아래처럼 작성하면 된다.

# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
  VERSION 1.0
  DESCRIPTION "CMAKE 연습"
  LANGUAGES CXX C)

1.2 message()

VERSION 1.0 을 기입함에 따라 PROJECT_VERSION 같은 전역변수들이 생성되는데, message() 명령어로 확인할 수 있다.

# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
  VERSION 1.0
  DESCRIPTION "CMAKE 연습"
  LANGUAGES CXX C)
 
message("Proejct 버전 : ${PROJECT_VERSION}")
message("Proejct global path : ${PROJECT_SOURCE_DIR}")

최상위 폴더에서 $ cmake . 을 실행하면 아래처럼 출력이 된다.

$ cmake .
Proejct 버전 : 1.0
-- Configuring done (0.0s)
-- Generating done (0.0s)
-- Build files have been written to: /Users/basamg/cpp/cmake_ex

(참고: cmake . 생성물은 직접 삭제해주자.)

1.3 set()

직접 변수를 설정해줄 수도 있다. (set 명령어의 주 역할은 내부변수에 값을 넣어주는 것이긴 하다. 후술예정)

data 폴더를 생성하고,

cmake_ex
├── CMakeLists.txt
├── data
└── src

set 명령어로 DATA_DIR 이라는 변수를 직접 생성해보자

# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
  VERSION 1.0
  DESCRIPTION "CMAKE 연습"
  LANGUAGES CXX C)
 
set(DATA_DIR ${PROJECT_SOURCE_DIR}/data)
 
message("Proejct 버전 : ${PROJECT_VERSION}")
message("Proejct global path : ${PROJECT_SOURCE_DIR}")
message("DATA 폴더 : ${DATA_DIR}")

아래 명령어를 실행해 DATA_DIR 변수를 확인할 수 있다. (이는 상속되어 하위 폴더에서 계속 사용할 수 있다.)

$ cmake .
...
...
Proejct 버전 : 1.0
Proejct global path : /Users/basamg/cpp/cmake_ex
DATA 폴더 : /Users/basamg/cpp/cmake_ex/data
...
...

2. sub directory 생성하기

src 폴더 내에 ex1 폴더를 생성하고, CMakeLists.txt 를 생성하자. 아래처럼 만들면 된다.

cmake_ex
├── CMakeLists.txt
├── data
└── src
    └── ex1 1
        └── CMakeLists.txt ....(2)

2.1 get_file_component() , string()

CMakeLists.txt (2) 를 아래처럼 작성해보자.

# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
 
message("현재 프로젝트 이름 : ${PROJECT_NAME}")

get_file_component 를 이용해 현재 프로젝트의 이름을 뽑아올 수 있다. ex1 1 폴더로 들어가서 $ cmake . 명령어를 실행하면 아래와 같이 출력된다.

$ cmake .
...
...
현재 프로젝트 이름 : ex1 1
...
...

위처럼 공백을 포함하는 경우에 대처하기 위해서 아래처럼 CMakeLists 를 수정하자.

# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
 
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
 
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
message("현재 프로젝트 이름 : ${PROJECT_NAME}")

빌드를 진행하면 아래처럼 출력되는 것을 확인할 수 있다. (물론 폴더명에 공백을 쓰는 개발자는 없을 것이다)

$ cmake .
...
...
현재 프로젝트 이름 : ex1 1
현재 프로젝트 이름 : ex1_1
...
...

2.2 set()

이제, 컴파일러에게 사용할 언어의 버전을 명시해줄 수 있다. cpp 를 비롯한 여러 언어들은 새로운 기능을 추가하고, 안정성 문제가 있는 기능들을 삭제하기도 하며 발전하고있다.

대표적인 예로, smart pointer 의 도입과, 템플릿 함수인 make_unique 제공 등등이 있다. 언어의 버전을 명시해놓지 않으면, 해당 코드를 실행하는 다른 환경에서 오류가 발생할 수 있다.

CMAKE_CXX_STANDARD 는 cmake 에서 사용하는 내부변수인데, set() 명령어로 직접 옵션을 달아줄 수 있다.

# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
 
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
 
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
 
project(PROJECT_NAME
  LANGUAGES CXX C
)
 
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

3. 소스 코드 작성하기

hello world 출력하는 간단한 소스코드를 작성하자.

ex1 1/main.cpp 를 아래처럼 작성하자.

#include <iostream>
int main() 
{ std::cout << "Hell World" << std::endl; }

4. 실행파일 생성

"이제, 실행파일을 만들어라" 라는 규칙을 명시해주면 된다.

4.1 add_executable()

# ex1 1/CMakeLists.txt
get_filename_component(PROJECT_NAME ${CMAKE_CURRENT_LIST_DIR} NAME)
 
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
 
string(REPLACE " " "_" PROJECT_NAME ${PROJECT_NAME})
message("현재 프로젝트 이름 : ${PROJECT_NAME}")
 
project(${PROJECT_NAME}
  LANGUAGES CXX C
)
 
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
 
add_executable(${PROJECT_NAME} main.cpp)

4.2 add_subdirectory()

최상위 폴더의 CMakeLists.txt 에 add_subdirectory() 명령어를 이용해 ex1 1 폴더를 빌드 시스템에 포함시키자.

# CMakeLists.txt
cmake_minimum_required(VERSION 3.31)
project(cmake_ex
  VERSION 1.0
  DESCRIPTION "CMAKE 연습"
  LANGUAGES CXX C)
 
set(DATA_DIR ${PROJECT_SOURCE_DIR}/data)
 
message("Proejct 버전 : ${PROJECT_VERSION}")
message("Proejct global path : ${PROJECT_SOURCE_DIR}")
message("DATA 폴더 : ${DATA_DIR}")
 
add_subdirectory("${PROJECT_SOURCE_DIR}/src/ex1 1")

5. 빌드

이제 최상위 폴더에서 build 폴더를 생성하자. $ mkdir build && cd build

$ cmake .. 으로 빌드 파일을 생성하고, $ make 로 빌드하자.

실행파일이 build/src/ex1 1/ex1_1 로 생성된다.

현재 위치가 build 라면, $ ./src/ex1 1/ex1_1 를 실행하면! ![[2026-02-15_11-59-02.png]]

방명록

Visitor Authentication Required

안녕하세요. 방명록을 남기시려면 로그인/회원가입 부탁드립니다. 매너챗 부탁드려요.

Log In / Sign Up
This blog is based on this source code on GitHub.